package db

import (
	"database/sql"
	"fmt"
	"strings"
	"ubt-aio-service/app/pkg/conf"
	"ubt-aio-service/app/pkg/logger"
	"ubt-aio-service/app/utils"

	_ "github.com/lib/pq"
	"golang.org/x/text/cases"
	"golang.org/x/text/language"
)

var Conn *sql.DB

// InitPgsql 连接MySQL数据库
func InitPgsql() *sql.DB {
	cfg := conf.Cfg.DbConf
	var err error
	dataSrcName := "host=" + cfg.DbHost + " port=" + cfg.DbPort + " user=" + cfg.Usname + " password=" + cfg.Passwd + " dbname=" + cfg.DbName + " sslmode=disable"
	if Conn, err = sql.Open("postgres", dataSrcName); err != nil {
		panic("数据库连接失败。" + err.Error())
		return nil
	}
	if err = Conn.Ping(); err != nil {
		panic("数据库Ping连接失败。" + err.Error())
		return nil
	}
	fmt.Println("数据库连接成功～！")
	return Conn
}

// CudData 操作数据，增、删、改均调用该方法
func CudData(sqlStr string, args ...any) *utils.ResJson {
	logger.Debug(sqlStr)
	logger.Debug(args)
	stmt, err := Conn.Prepare(sqlStr)
	if err != nil {
		logger.Error("数据库预处理失败。" + err.Error())
		return utils.DbErr
	}
	defer func(stmt *sql.Stmt) {
		if err = stmt.Close(); err != nil {
			return
		}
	}(stmt)
	if _, err = stmt.Exec(args...); err == nil {
		return utils.Succeed
	}
	logger.Error("数据处理失败。" + err.Error())
	return utils.DataErr
}

// GetOne 获取一行记录
func GetOne(sqlStr string, args ...any) *utils.ResJson {
	logger.Debug(sqlStr)
	logger.Debug(args)
	// 查询数据
	rows, err := Conn.Query(sqlStr, args...)
	// 最终关闭数据库连接
	defer func(rows *sql.Rows) {
		if err = rows.Close(); err != nil {
			logger.Error("关闭数据查询失败。" + err.Error())
			return
		}
	}(rows)
	if err == nil {
		var dbMap map[string]any
		for rows.Next() {
			dbMap = scanRow(rows)
			if dbMap != nil {
				break
			}
		}
		if len(dbMap) > 0 {
			return &utils.ResJson{Code: utils.Succeed.Code, Msg: utils.Succeed.Msg, Data: dbMap}
		}
		return utils.NoData
	}
	logger.Error("数据获取失败。" + err.Error())
	return utils.PackErr
}

// GetAll 获取多行记录
func GetAll(sqlStr string, args ...any) *utils.ResJson {
	logger.Debug(sqlStr)
	logger.Debug(args)
	// 查询数据
	rows, err := Conn.Query(sqlStr, args...)
	// 最终关闭数据库连接
	defer func(rows *sql.Rows) {
		if err = rows.Close(); err != nil {
			logger.Error("关闭数据查询失败。" + err.Error())
			return
		}
	}(rows)
	if err == nil {
		result := make([]map[string]any, 0)
		var (
			dbMap map[string]any
			flag  uint8
		)
		for rows.Next() {
			if dbMap = scanRow(rows); dbMap != nil {
				result = append(result, dbMap)
			} else {
				flag = 1
				break
			}
		}
		if flag == 0 {
			if len(result) > 0 {
				return &utils.ResJson{Code: utils.Succeed.Code, Msg: utils.Succeed.Msg, Data: result}
			} else {
				return utils.NoData
			}
		}
	}
	logger.Error("数据获取失败。" + err.Error())
	return utils.PackErr
}

// scanRow 将数据库字段转换为Map
func scanRow(rows *sql.Rows) map[string]any {
	if columns, err := rows.Columns(); err == nil {
		vals := make([]any, len(columns))
		valsPtr := make([]any, len(columns))
		for i := range vals {
			valsPtr[i] = &vals[i]
		}
		if err = rows.Scan(valsPtr...); err == nil {
			r := make(map[string]any)
			c := cases.Title(language.Dutch)
			for i, v := range columns {
				// 将数据表中各字段下划线转成驼峰
				v = strings.Replace(v, "_", " ", -1)
				v = c.String(v)
				v = strings.Replace(v, " ", "", -1)
				v = strings.ToLower(string(v[0])) + v[1:]
				if va, ok := vals[i].([]byte); ok {
					r[v] = string(va)
				} else {
					r[v] = vals[i]
				}
			}
			return r
		}
		logger.Error("数据字段转换失败。" + err.Error())
	}
	return nil
}
